package com.lanyou.esb.service;

import java.math.BigDecimal;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections4.map.MultiKeyMap;
import org.apache.commons.lang3.time.FastDateFormat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.lanyou.cook.common.Constants;
import com.lanyou.esb.common.CommonUtils;
import com.lanyou.esb.datadictionary.PeriodType;
import com.lanyou.esb.repository.ServiceMonitorRepository;
import com.lanyou.esb.vo.PfThroughputVo;
import com.lanyou.esb.vo.PfThroughputVo.Series;
import com.lanyou.esb.vo.PfThroughputVo.Categories;
import com.lanyou.esb.web.param.PfThroughputParam.Entry;

/**
 * 平台吞吐量/平台吞吐率服务
 * 
 * @author Davey.wu
 */
@Service
public class PfThroughputService {
	@Autowired
	private ServiceMonitorRepository serviceMonitorRepository;
	private static FastDateFormat FASTDATEFORMAT_YYYYMMDDHHMMSS = FastDateFormat
			.getInstance(Constants.DATETIME_PATTERN_1);
	private static FastDateFormat FASTDATEFORMAT_YYYYMMDD = FastDateFormat
			.getInstance(Constants.DATETIME_PATTERN_YYYYMMDD);
	private static FastDateFormat FASTDATEFORMAT_YYYYMM = FastDateFormat
			.getInstance(Constants.DATETIME_PATTERN_YYYYMM);

	/**
	 * 查找平台吞吐量信息
	 * 
	 * @param period
	 *            :周期
	 * @param fields
	 *            ：领域
	 * 
	 * @return
	 * @throws ParseException
	 */
	public PfThroughputVo findPfThroughputInfo(boolean selectAll,
			List<Entry> fields, String period, Date end) throws ParseException {
		Calendar endC = Calendar.getInstance();
		endC.setTime(end);
		// 消除时分秒
		endC.set(Calendar.HOUR_OF_DAY, 0);
		endC.set(Calendar.MINUTE, 0);
		endC.set(Calendar.SECOND, 0);
		endC.set(Calendar.MILLISECOND, 0);
		Calendar startC = Calendar.getInstance();
		startC.setTime(end);
		// 消除时分秒
		startC.set(Calendar.HOUR_OF_DAY, 0);
		startC.set(Calendar.MINUTE, 0);
		startC.set(Calendar.SECOND, 0);
		startC.set(Calendar.MILLISECOND, 0);
		// 日期列表
		List<String> dateList = null;
		// 最近一周平台吞吐量
		if (PeriodType.WEEK.ValueCode.equals(period)) {
			// 前7天
			startC.add(Calendar.DAY_OF_MONTH, -7);
			// 获取日期列表
			dateList = getDateList(startC.getTime(), endC.getTime(),
					Calendar.DAY_OF_MONTH, FASTDATEFORMAT_YYYYMMDD, new int[] {
							Calendar.MILLISECOND, Calendar.SECOND,
							Calendar.MINUTE, Calendar.HOUR_OF_DAY });
			// 获取数据
			return findPfThroughputInfoGroupByDay(selectAll, dateList, fields,
					FASTDATEFORMAT_YYYYMMDD.format(startC.getTime()),
					FASTDATEFORMAT_YYYYMMDD.format(endC.getTime()),
					FASTDATEFORMAT_YYYYMMDDHHMMSS);
		}
		// 最近一个月平台吞吐量
		if (PeriodType.MONTH.ValueCode.equals(period)) {
			// 前一个月
			startC.add(Calendar.MONTH, -1);
			// 获取日期列表
			dateList = getDateList(startC.getTime(), endC.getTime(),
					Calendar.DAY_OF_MONTH, FASTDATEFORMAT_YYYYMMDD, new int[] {
							Calendar.MILLISECOND, Calendar.SECOND,
							Calendar.MINUTE, Calendar.HOUR_OF_DAY });
			// 获取数据
			return findPfThroughputInfoGroupByDay(selectAll, dateList, fields,
					FASTDATEFORMAT_YYYYMMDD.format(startC.getTime()),
					FASTDATEFORMAT_YYYYMMDD.format(endC.getTime()),
					FASTDATEFORMAT_YYYYMMDDHHMMSS);
		}
		// 最近一个年平台吞吐量
		if (PeriodType.YEAR.ValueCode.equals(period)) {
			// 前一年
			startC.add(Calendar.YEAR, -1);
			// 获取日期列表
			dateList = getDateList(startC.getTime(), endC.getTime(),
					Calendar.MONTH, FASTDATEFORMAT_YYYYMM, new int[] {
							Calendar.MILLISECOND, Calendar.SECOND,
							Calendar.MINUTE, Calendar.HOUR_OF_DAY,
							Calendar.DAY_OF_MONTH });
			// 获取数据
			return findPfThroughputInfoGroupByMonth(selectAll, dateList,
					fields, FASTDATEFORMAT_YYYYMMDD.format(startC.getTime()),
					FASTDATEFORMAT_YYYYMMDD.format(endC.getTime()),
					FASTDATEFORMAT_YYYYMM);
		}
		// 默认返回空集
		return null;
	}

	/**
	 * 查找平台吞吐量率信息
	 * 
	 * @param period
	 *            :周期
	 * @param fields
	 *            ：领域
	 * @param date
	 *            ：时间点
	 * 
	 * @return
	 * @throws ParseException
	 */
	public PfThroughputVo findPfThroughputRateInfo(boolean selectAll,
			List<Entry> fields, String period, Date end) throws ParseException {
		// 获取平台流量信息
		PfThroughputVo pfthroughputVo = findPfThroughputInfo(selectAll, fields,
				period, end);
		// 一天分钟数
		int minute = 24 * 60;
		for (Series series : pfthroughputVo.getSeries()) {
			List<Double> values = series.getValues();
			for (int i = 0; i < values.size(); ++i) {
				// 计算吞吐率：当日总流量%分钟数
				values.set(i, values.get(i) / minute);
			}
		}
		return pfthroughputVo;
	}

	/**
	 * 查找平台吞吐量信息,以月为单位
	 * 
	 * @param selectAll
	 * 
	 * @param dateList
	 * @param fields
	 * @param startDate
	 * @param endDate
	 * @param format
	 * @return
	 * @throws ParseException
	 */
	private PfThroughputVo findPfThroughputInfoGroupByMonth(boolean selectAll,
			List<String> dateList, List<Entry> fields, String startDate,
			String endDate, FastDateFormat format) throws ParseException {

		// 日期列表为空，且非选全部，且没选领域，不查询数据
		if (dateList == null || dateList.isEmpty()
				|| (!selectAll && (fields == null || fields.isEmpty()))) {
			return null;
		}
		PfThroughputVo vo4All = null;
		// 选择全部
		if (selectAll) {
			vo4All = formatPfThroughputInfoGroupByDay(dateList,
					serviceMonitorRepository.finePfThroughputInfoGroupByMonth(
							startDate, endDate), FASTDATEFORMAT_YYYYMM, format);
		}
		PfThroughputVo v04Fields = null;
		// 选择领域
		if (fields != null && !fields.isEmpty()) {
			List<String> fieldIds = new ArrayList<>(fields.size());
			for (Entry entry : fields) {
				fieldIds.add(entry.getId());
			}
			// 查找指定领域
			v04Fields = formatPfThroughputInfoGroupByFieldAndDay(dateList,
					fields,
					serviceMonitorRepository
							.finePfThroughputInfoGroupByFieldAndMonth(fieldIds,
									startDate, endDate), FASTDATEFORMAT_YYYYMM,
					format);
		}

		if (!selectAll || vo4All == null) {
			return v04Fields;
		}
		if (v04Fields.getSeries() == null || v04Fields.getSeries().isEmpty()) {
			return vo4All;
		}
		// 合并结果集
		if (vo4All.getSeries() != null) {
			v04Fields.getSeries().addAll(vo4All.getSeries());
		}
		return v04Fields;

	}

	/**
	 * 查找平台吞吐量信息,以天为单位
	 * 
	 * @param selectAll
	 * 
	 * @param dateList
	 * @param fields
	 * @param startDate
	 * @param endDate
	 * @param categoriesFormat
	 * @return
	 * @throws ParseException
	 */
	private PfThroughputVo findPfThroughputInfoGroupByDay(boolean selectAll,
			List<String> dateList, List<Entry> fields, String startDate,
			String endDate, FastDateFormat categoriesFormat)
			throws ParseException {
		// 日期列表为空，且非选全部，且没选领域，不查询数据
		if (dateList == null || dateList.isEmpty()
				|| (!selectAll && (fields == null || fields.isEmpty()))) {
			return null;
		}
		PfThroughputVo vo4All = null;
		// 选择全部
		if (selectAll) {
			vo4All = formatPfThroughputInfoGroupByDay(dateList,
					serviceMonitorRepository.finePfThroughputInfoGroupByDay(
							startDate, endDate), FASTDATEFORMAT_YYYYMMDD,
					categoriesFormat);
		}
		PfThroughputVo v04Fields = null;
		// 选择领域
		if (fields != null && !fields.isEmpty()) {
			List<String> fieldIds = new ArrayList<>(fields.size());
			for (Entry entry : fields) {
				fieldIds.add(entry.getId());
			}
			// 查找指定领域
			v04Fields = formatPfThroughputInfoGroupByFieldAndDay(dateList,
					fields,
					serviceMonitorRepository
							.finePfThroughputInfoGroupByFieldAndDay(fieldIds,
									startDate, endDate),
					FASTDATEFORMAT_YYYYMMDD, categoriesFormat);
		}

		if (!selectAll || vo4All == null) {
			return v04Fields;
		}
		if (v04Fields.getSeries() == null || v04Fields.getSeries().isEmpty()) {
			return vo4All;
		}
		// 合并结果集
		if (vo4All.getSeries() != null) {
			v04Fields.getSeries().addAll(vo4All.getSeries());
		}
		return v04Fields;
	}

	/**
	 * 对查询结果进行重组，以日期分组
	 * 
	 * @param dateList
	 * @param list
	 * @param format
	 * @param categoriesFormat
	 * @return
	 * @throws ParseException
	 */
	private PfThroughputVo formatPfThroughputInfoGroupByDay(
			List<String> dateList, List<Object[]> list, FastDateFormat format,
			FastDateFormat categoriesFormat) throws ParseException {
		if (list == null || list.isEmpty()) {
			list = new ArrayList<>(0);
		}

		Map<String, Double> map = new HashMap<>(dateList.size());
		for (Object[] object : list) {
			if (object[0] == null) {
				continue;
			}
			map.put((String) object[0], (object[1] == null) ? 0
					: (((BigDecimal) object[1]).doubleValue()));
		}
		PfThroughputVo result = new PfThroughputVo();
		// 分类数据
		Categories categories = new Categories();
		List<String> categryValues = new ArrayList<>(dateList.size());
		categories.setValues(categryValues);
		result.setCategories(categories);
		// 系列数据
		List<Series> seriesList = new ArrayList<>(1);
		Series series = new Series();
		List<Double> seriesValues = new ArrayList<>(dateList.size());
		series.setName(CommonUtils.SERIES_NAME_ALL);
		series.setValues(seriesValues);
		seriesList.add(series);
		result.setSeries(seriesList);

		for (int i = 0; i < dateList.size(); ++i) {
			String key = dateList.get(i);
			Double value = map.get(key);
			categryValues.add(categoriesFormat.format(format.parse(key)));
			seriesValues.add(value == null ? 0 : value);
		}

		return result;
	}

	/**
	 * 对查询结果进行重组，以领域和日期分组
	 * 
	 * @param fields
	 * @param categoriesFormat
	 * @param fields2
	 * @param startDate
	 * @param endDate
	 * @return
	 * @throws ParseException
	 */
	private PfThroughputVo formatPfThroughputInfoGroupByFieldAndDay(
			List<String> dateList, List<Entry> fields, List<Object[]> list,
			FastDateFormat format, FastDateFormat categoriesFormat)
			throws ParseException {
		if (list == null) {
			list = new ArrayList<>(0);
		}
		PfThroughputVo result = new PfThroughputVo();
		// Y轴数据
		Categories categories = new Categories();
		List<String> categoryValues = new ArrayList<>(dateList.size());
		categories.setValues(categoryValues);
		result.setCategories(categories);
		// X轴数据
		List<Series> seriesList = new ArrayList<>(fields.size());
		result.setSeries(seriesList);

		// 领域ID/名对
		// Map<String, String> fieldMap = new HashMap<>();
		// 未分领域的原始数据
		MultiKeyMap<String, Double> map = new MultiKeyMap<>();
		for (Object[] object : list) {
			if (object[2] == null) {
				continue;
			}
			String fieldId = (String) object[0];
			// String fieldName = (String) object[1];
			String date = (String) object[2];
			double value = (object[3] == null) ? 0 : (((BigDecimal) object[3])
					.doubleValue());
			// 保存领域ID/名对
			// fieldMap.put(fieldId, fieldName);
			// 按领域和日期保存
			map.put(fieldId, date, value);
		}
		for (String date : dateList) {
			categoryValues.add(categoriesFormat.format(format.parse(date)));
		}
		for (Entry entry : fields) {
			if (CommonUtils.SERIES_NAME_ALL.equals(entry.getName())) {
				continue;
			}
			Series series = new Series();
			List<Double> seriesValues = new ArrayList<>(dateList.size());
			series.setName(entry.getName());
			series.setValues(seriesValues);
			seriesList.add(series);

			// 统计每个领域的数据
			for (int j = 0; j < dateList.size(); ++j) {
				Double value = map.get(entry.getId(), dateList.get(j));
				if (value == null) {
					seriesValues.add(0.0);
					continue;
				}
				seriesValues.add(value);
			}
		}

		return result;
	}

	/**
	 * 获取日期列表
	 * 
	 * @param startDate
	 *            ：开始日期
	 * @param endDate
	 *            ：结束日期
	 * @return
	 */
	private List<String> getDateList(Date startDate, Date endDate, int field,
			FastDateFormat format, int[] clearFields) {
		if (startDate == null || endDate == null) {
			return new ArrayList<>(0);
		}
		Calendar startC = Calendar.getInstance();
		startC.setTime(startDate);
		Calendar endC = Calendar.getInstance();
		endC.setTime(endDate);
		// 清除不需要的日期字段
		if (clearFields != null) {
			for (int i : clearFields) {
				startC.set(i, 0);
				endC.set(i, 0);
			}
		}
		List<String> list = new ArrayList<>();
		// 获取日期列表
		while (startC.before(endC)) {
			startC.add(field, 1);
			list.add(format.format(startC.getTime()));
		}
		return list;
	}
}
